package org.jfonia.connect5.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.jfonia.connect5.basics.BasicNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.basics.ValueNode;

/**
 * @author wijnand.schepens@hogent.be
 */
public class ArrayListNode<T> implements List<T>
{
	protected List<T> elements;

	protected IndexNotifier additionNode; // value is index of element last added
	protected IndexNotifier removalNode;  // value is index of element last removed

	public ArrayListNode()
	{
		elements = new ArrayList<T>();
		additionNode = new IndexNotifier();
		removalNode = new IndexNotifier();
	}



	// getters

	public boolean contains(Object o)
	{
		return elements.contains(o);
	}

	public T get(int index)
	{
		return elements.get(index);
	}

	public int indexOf(Object o)
	{
		return elements.indexOf(o);
	}

	public boolean isEmpty()
	{
		return elements.isEmpty();
	}

	public int lastIndexOf(Object o)
	{
		return elements.lastIndexOf(o);
	}

	public int size()
	{
		return elements.size();
	}


	// modifiers

	public void add(int index, T x)
	{
		elements.add(index, x);
		additionNode.setValue(index);
	}

	public void add(int index, T x, Observer source)
	{
		elements.add(index, x);
		additionNode.setValue(index, source);
	}


	public boolean add(T x)
	{
		this.add(elements.size(), x);
		return true;
	}

	public void add(T x, Observer source)
	{
		this.add(elements.size(), x, source);
	}

	public boolean addAll(Collection<? extends T> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public boolean addAll(int index, Collection<? extends T> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public void clear()
	{
		while (!isEmpty())
			remove(elements.size() - 1);
	}

	public void clear(Observer source)
	{
		while (!isEmpty())
			remove(elements.size() - 1, source);
	}



	public boolean remove(Object o)
	{
		int i = indexOf(o);
		if (i == -1)
			return false;
		remove(i);
		return true;
	}

	public boolean remove(Object o, Observer source)
	{
		int i = indexOf(o);
		if (i == -1)
			return false;
		remove(i, source);
		return true;
	}

	public T remove(int index)
	{
		T el = elements.remove(index);
		removalNode.setValue(index);
		return el;
	}

	public void remove(int index, Observer source)
	{
		elements.remove(index);
		removalNode.setValue(index, source);
	}

	public boolean removeAll(Collection<?> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public boolean retainAll(Collection<?> c)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}

	public T set(int index, T element)
	{
		return elements.set(index, element);
	}


	// iterators

	public Iterator<T> iterator()
	{
		return elements.iterator();
	}

	public ListIterator<T> listIterator()
	{
		return elements.listIterator();
	}

	public ListIterator<T> listIterator(int index)
	{
		return elements.listIterator(index);
	}

	public Object[] toArray()
	{
		return elements.toArray();
	}

	public <T> T[] toArray(T[] a)
	{
		return elements.toArray(a);
	}

	public boolean containsAll(Collection<?> c)
	{
		return elements.containsAll(c);
	}

	public List<T> subList(int fromIndex, int toIndex)
	{
		throw new UnsupportedOperationException("Not supported yet.");
	}






	public ValueNode<Integer> getAdditionNode() // note: disguised as ValueNode: user should in principle not change value
	{
		return additionNode;
	}

	public ValueNode<Integer> getRemovalNode() // note: idem
	{
		return removalNode;
	}




	private class IndexNotifier extends BasicNode implements ValueNode<Integer>
	{
		int index;

		void setValue(int index) {
			this.index = index;
			notifyObservers();
		}

		void setValue(int index, Observer source) {
			this.index = index;
			notifyObserversExcept(source);
		}

		public Integer getValue()
		{
			return index;
		}
	}
}
